/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO

Authors: Nitay Megides
		 Rachel Banino

Project: Exercise 3

Description:
A general module for general functions. Used throughout the project
oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/

#define _CRT_SECURE_NO_WARNINGS

#include "General.h"
#include <stdio.h>
#include "Manager.h"

FILE* outputFile;
FILE* errorFile;

HANDLE hasErrorMutex;
HANDLE faceFoundMutex;


BOOL FileInitialize(const char* outputFilename, const char* errorFilename)
{
	hasErrorMutex = CreateMutex(NULL, FALSE, NULL);
	if (hasErrorMutex == NULL)
	{
		return FALSE;
	}
	faceFoundMutex = CreateMutex(NULL, FALSE, NULL);
	if (faceFoundMutex == NULL)
	{
		return FALSE;
	}

	outputFile = NULL;
	errorFile = NULL;

	outputFile = fopen(outputFilename, "w");
	errorFile = fopen(errorFilename, "w");

	return ((errorFile != NULL) && (outputFile == NULL));
}

void FileFree()
{
	if (hasErrorMutex != NULL)
		CloseHandle(hasErrorMutex);

	if (faceFoundMutex != NULL)
		CloseHandle(faceFoundMutex);

	if (outputFile != NULL)
		fclose(outputFile);
	if (errorFile != NULL)
		fclose(errorFile);
}

BOOL CheckError()
{
	// After I get it the first time, the mutex will be locked
	return (WaitForSingleObject(hasErrorMutex, 0) != WAIT_OBJECT_0);
}

BOOL CheckFaceFound()
{
	// After I get it the first time, the mutex will be locked
	return (WaitForSingleObject(faceFoundMutex, 0) != WAIT_OBJECT_0);
}

void ReportIdenticalFacesFound( PArea face1, PArea face2 )
{
	PArea faceA;
	PArea faceB;

	// Sets the error flag and the face found flag
	if (CheckError() || CheckFaceFound())
		return;

	// I'm using this face swap to make automatic testing easier
	// This way the higher X will always be written first
	if (face1->X > face2->X)
	{
		faceA = face1;
		faceB = face2;
	}
	else
	{
		faceA = face2;
		faceB = face1;
	}

	printf("(%d,%d)<->(%d,%d)", faceA->Y, faceA->X, faceB->Y, faceB->X);
	fprintf(outputFile, "(%d,%d)<->(%d,%d)", faceA->Y, faceA->X, faceB->Y, faceB->X);
}

void ReportError(const char* format, ...)
{
	int stringLength;
	va_list l_tAp;
	char theString[MAX_LINE_LEN];
	const int l_iPrefixLen = 0;

	// Get the error
	va_start(l_tAp, format);
	stringLength = vsprintf(theString, format, l_tAp);
	printf("%s", theString);

	// Sets the error flag
	if (!CheckError())
	{
		// Start Termination sequence
		TerminateProgram();

		fprintf(errorFile, "%s", theString);
	}
}

DWORD WaitForMultipleMultipleObjects( DWORD nCount, const HANDLE *lpHandles, DWORD dwMilliseconds )
{
	DWORD waitResult = WAIT_OBJECT_0;
	int countLeft = nCount;
	int currentPosition = 0;

	while ((countLeft > 0) && waitResult == WAIT_OBJECT_0)
	{
		waitResult = WaitForMultipleObjects(min(countLeft, 64), &lpHandles[currentPosition], TRUE, dwMilliseconds);

		countLeft -= MAXIMUM_WAIT_OBJECTS;
		currentPosition += MAXIMUM_WAIT_OBJECTS;
	}
	
	return waitResult;
}
